#include "dis_pset.hpp"
#include <cstring>

//原始网格读取函数
//content: 文件内容指针
//file_len: 文件长度
//valid: 记录有效数据数量
//tid: 线程编号
void dis_pset::read(int type,const char* content, long long file_len, int *valid, int tid){
    long long ptr = 0;  //使用ptr作为循环指针
    
    //跳过首行
    while (content[ptr] != '\n')
        ++ptr;

    //将读取文件按字符长度进行数据划分、任务分发
    long long mend = file_len;
    //余数部分交由最后一个线程处理
    if (thread_num != 0) {
        int period = mend - ptr;
        int seg = period / (thread_num + 1);
        ptr += tid * seg;
        if (tid != thread_num)
            mend = ptr + seg;
    }

    int mysize = 200;  //数据指针初始大小
    double* mydata = new double[mysize]; //有效数据指针
    //跳过各线程开头不完整的数据
    //如线程3读入数据正好位于某一个数字中间，则线程3跳过该数据，交由线程2读取
    if (tid != 0 && might_be_num(content[ptr - 1])) {
        while (might_be_num(content[ptr])) {
            ++ptr;
        }
    }

    //若文件类型为目标文件时，跳过第一个数字，即第一个点的编号值
    //此时继续读取，读取逻辑与原始网格文件逻辑相同
    //不过原本原始网格对应的应力分量值，在此时读取的是下一个点的编号
    if(type==1&&tid==0)
        get_a_num(content, ptr, mydata[0]);

    //循环遍历读取数据
    while (ptr < mend) {
        //若读取数据超过指针大小，则重新分配空间
        if (valid[tid] >= mysize-2) {
            //1.5倍扩容
            mysize *= 1.5;
            double* tmp = new double[mysize];
            memcpy(tmp, mydata, valid[tid] * sizeof(double));
            delete mydata;
            mydata = tmp;
        }
        
        //读取数据
        mydata[valid[tid]] = get_a_num(content, ptr, mydata[valid[tid]]);
        //更新有效值
        ++valid[tid];

        //跳过非数字字符
        while (ptr < mend && !might_be_num(content[ptr])) {
            ++ptr;
        }
    }

    //线程同步
    thm.thread_sync(tid);

    if (tid == 0) {
        size = 0;
        
        //文件类型为目标网格时，跳过了第一个数，所以此处+1
        if(type==1)
            size++;
        //由0号线程也就是主线程来统计格线程读取有效数据
        for (int i = 0; i < thread_num + 1; i++) {
            size += valid[i];
        }
        //主线程分配dis_point的实际大小
        data = new dis_point[size / 4];
        size /= 4;
    }
    
    //各线程计算自己读取数据在最终数据指针空间的位置
    int beg = 0;
    for (int i = 0; i < tid; i++) {
        beg += valid[i];
    }
    thm.thread_sync(tid);
    
    //汇总数据
    memcpy(((double *)data) + beg, mydata, valid[tid] * sizeof(double));

    delete[]mydata;
}

//将要求数据输出至指定文件
//obj: 文件内存映射对象指针
//str: 输出内容
//tid: 线程id
void dis_pset::write(FileMapping* obj,string *str, int tid ) {
    //文件开头
    if (tid == 0) {
        str[tid] += "No.\tx\ty\tz\tval\n";
    }

    //将size划分到各线程
    int ptr = 0;
    int end = size;
    if (thread_num != 0) {
        int seg = (end - ptr) / (thread_num + 1);
        ptr += tid * seg;
        if (tid != thread_num)
            end = ptr + seg;
    }

    //循环遍历数据，构造string str
    while (ptr < end) {
        str[tid] += to_string(ptr) + "\t" +
            to_string(data[ptr].x) + "\t" +
            to_string(data[ptr].y) + "\t" +
            to_string(data[ptr].z) + "\t" +
            to_string(data[ptr].val) + "\n";
        ++ptr;
    }
    //线程同步
    thm.thread_sync();

    //主线程将string依次输出至文件
    if (tid == 0) {
        for (int i = 0; i < thread_num + 1; i++)
            obj->write(str[i]);
    }

}